package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.unit.DataUnit;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseSearchDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.dto.LearningThisWeekCountDto;
import com.tianji.learning.domain.entity.LearningLesson;
import com.tianji.learning.domain.vo.LearningLessonVo;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author author
 */
@Slf4j
@Service
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
    @Autowired
    private CourseClient courseClient;
    @Autowired
    private CatalogueClient catalogueClient;
    @Autowired
    private LearningLessonMapper learningLessonMapper;
    @Autowired
    private LearningRecordMapper learningRecordMapper;

    @Override
    public PageDTO<LearningLessonVo> pageQuery(PageQuery query) {
        Long userId = UserContext.getUser();
        //fenye
        Page<LearningLesson> page = query.toMpPage(query.getSortBy(), query.getIsAsc());
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getUserId, userId);
        //cha
        this.page(page, queryWrapper);

        List<LearningLesson> lessons = page.getRecords();
        if (CollectionUtil.isEmpty(lessons)) {
            return PageDTO.empty(page);
        }
        // feign courseClient-> 根据课程id查询课程信息：name、cover、sections
        List<Long> courseIds = lessons.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
        if (CollectionUtil.isEmpty(simpleInfoList)) {
            log.error("根据课程ids：{}查询不到课程信息", courseIds);
            throw new BizIllegalException("网络异常，请稍后重试");
        }
        // 填充
        List<LearningLessonVo> learningLessonVos = new ArrayList<>();
        for (LearningLesson lesson : lessons) {
            LearningLessonVo learningLessonVo = BeanUtil.copyProperties(lesson, LearningLessonVo.class);
            CourseSimpleInfoDTO course = getCourse(lesson.getCourseId(), simpleInfoList);
            learningLessonVo.setCourseName(course.getName());
            learningLessonVo.setCourseCoverUrl(course.getCoverUrl());
            learningLessonVo.setSections(course.getSectionNum());
            learningLessonVos.add(learningLessonVo);
        }
        return PageDTO.of(page, learningLessonVos);

    }

    @Override
    public void createLearningPlan(LearningPlanDTO planDTO) {
        Long userId = UserContext.getUser();
        this.lambdaUpdate()
                .set(LearningLesson::getWeekFreq, planDTO.getFreq())
                .set(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING.getValue())
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, planDTO.getCourseId())
                .update();
    }

    @Override
    @Transactional
    public void checkAndDeleteBeOver() {
        Long userId = UserContext.getUser();
        List<LearningLesson> list = this.lambdaQuery().eq(LearningLesson::getUserId, userId).
                ge(LearningLesson::getExpireTime, LocalDateTime.now()).list();
        if(CollectionUtil.isNotEmpty(list)){
            List<LearningLesson> collect = list.stream().map(lesson -> lesson.setStatus(LessonStatus.EXPIRED.getValue())).collect(Collectors.toList());
            this.updateBatchById(collect);
        }
        //TODO day02.5  spring task 定时任务
    }

    @Override
    public LearningPlanPageVO selectLearningPlan(PageQuery query) {
        Long userId = UserContext.getUser();
        //fenye
        Page<LearningLesson> page = this.lambdaQuery().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING.getValue())
                .in(LearningLesson::getStatus, Arrays.asList(LessonStatus.NOT_BEGIN.getValue(), LessonStatus.LEARNING.getValue(), LessonStatus.FINISHED.getValue()))
                .page(query.toMpPage("latest_learn_time", false));
        List<LearningLesson> lessons = page.getRecords();
        if (CollectionUtil.isEmpty(lessons)) {
            return null;
        }
        int weekFinished = 0;
        int totalPlan = 0;
        List<Long> courseIds = lessons.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> courseSimpleInfoDTOList = courseClient.getSimpleInfoList(courseIds);
        Map<Long, CourseSimpleInfoDTO> courseSimpleInfoDTOMap = courseSimpleInfoDTOList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        List<LearningPlanVO> planList = new ArrayList<>();
        //通过id 开始，结束时间查询 本周学了多少课
        LocalDate now = LocalDate.now();
        LocalDateTime weekBeginTime = DateUtils.getWeekBeginTime(now);
        LocalDateTime weekEndTime = DateUtils.getWeekEndTime(now);
        List<LearningThisWeekCountDto> dtoList = this.learningRecordMapper.selectLearningThisWeekCount(userId, weekBeginTime, weekEndTime);

        Map<Long, Integer> dtoMap = dtoList.stream().collect(Collectors.toMap(LearningThisWeekCountDto::getCourseId, LearningThisWeekCountDto::getCount));
        for (LearningLesson lesson : lessons) {
//            LearningPlanVO planVO = new LearningPlanVO();
            LearningPlanVO planVo = BeanUtil.copyProperties(lesson, LearningPlanVO.class);
            CourseSimpleInfoDTO courseSimpleInfoDTO = courseSimpleInfoDTOMap.get(lesson.getCourseId());
            planVo.setCourseName(courseSimpleInfoDTO.getName());
            planVo.setSections(courseSimpleInfoDTO.getSectionNum());
            Integer count = dtoMap.get(lesson.getCourseId());

            planVo.setWeekLearnedSections(count == null ? 0 : count);
            planList.add(planVo);
            totalPlan += lesson.getWeekFreq();
            weekFinished += count==null?0:count;// TODO
        }
        LearningPlanPageVO learningPlanPageVO = new LearningPlanPageVO();
        learningPlanPageVO.setTotal(page.getTotal());
        learningPlanPageVO.setList(planList);
        learningPlanPageVO.setWeekFinished(weekFinished);
        learningPlanPageVO.setWeekTotalPlan(totalPlan);
        return learningPlanPageVO;

    }

    @Override
    public LearningLessonVo now() {
        Long userId = UserContext.getUser();
        //查询最近一次正在学习的课程Leaning_Lesson
        //select *from learning_lesson where user_id=#{userId} order by latest_learn_time desc limit 1
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getUserId, userId);
        queryWrapper.eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue());
        queryWrapper.orderByDesc(LearningLesson::getLatestLearnTime);
        queryWrapper.last("limit 1");
        LearningLesson lesson = this.getOne(queryWrapper);
        if (lesson == null) {
            return null;
        }
        LearningLessonVo learningLessonVo = BeanUtil.copyProperties(lesson, LearningLessonVo.class);
        //查询总的课程数量
        //select count（*) from Learning_lesson where user_id=#{userId} and status in (0,1,2）)
        LambdaQueryWrapper<LearningLesson> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getUserId, userId);
        queryWrapper.in(LearningLesson::getStatus, Arrays.asList(LessonStatus.NOT_BEGIN.getValue(), LessonStatus.LEARNING.getValue(), LessonStatus.FINISHED.getValue()));
        int count = this.count(queryWrapper);
        learningLessonVo.setCourseAmount(count);
        //feign:courseCLient-》courseName、sections、
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(Arrays.asList(lesson.getCourseId()));
        if (CollectionUtil.isEmpty(simpleInfoList)) {
            log.error("根据课程ids：{}查询不到课程信息", lesson.getCourseId());
            throw new BizIllegalException("网络异常，请稍后重试");
        }
        CourseSimpleInfoDTO courseSimpleInfoDTO = simpleInfoList.get(0);
        learningLessonVo.setSections(courseSimpleInfoDTO.getSectionNum());
        learningLessonVo.setCourseName(courseSimpleInfoDTO.getName());
        learningLessonVo.setCourseCoverUrl(courseSimpleInfoDTO.getCoverUrl());
        //feign:CatalogueClient-》batchQueryCataLogue (ids)
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(Arrays.asList(lesson.getLatestSectionId()));
        if (CollectionUtil.isEmpty(cataSimpleInfoDTOS)) {
            log.error("根据目录ids：{}查询不到目录信息", lesson.getLatestSectionId());
            throw new BizIllegalException("网络异常，请稍后重试");
        }
        CataSimpleInfoDTO cataSimpleInfoDTO = cataSimpleInfoDTOS.get(0);
        learningLessonVo.setLatestSectionName(cataSimpleInfoDTO.getName());
        learningLessonVo.setLatestSectionIndex(cataSimpleInfoDTO.getCIndex());
        return learningLessonVo;
    }

    @Override
    public void deleteByCourseId(Long courseId) {
        //TODO day02 主动删除课程
        Long userId = UserContext.getUser();
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<LearningLesson>().eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, userId);
        learningLessonMapper.delete(queryWrapper);
    }

    @Override
    public Long isLessonValid(Long courseId) {
        //TODO day02 2.1检查课程是否有效
        Long userId = UserContext.getUser();
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getCourseId, courseId);
        queryWrapper.eq(LearningLesson::getUserId, userId);
        LearningLesson lesson = this.getOne(queryWrapper);
        if (Objects.isNull(lesson)) {
            log.error("用户：{}，课程：{}，课程无有效", userId, courseId);
            return null;
        }
        return lesson.getId();

    }

    @Override
    public LearningLessonVo selectByCourseId(Long courseId) {
        //TODO day02 3.1查询用户课表中指定课程状态
        Long userId = UserContext.getUser();
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getCourseId, courseId);
        queryWrapper.eq(LearningLesson::getUserId, userId);
        LearningLesson lesson = this.getOne(queryWrapper);
        if (Objects.isNull(lesson)) {
            //todo day02 3.1.1 注意点   对于未购买的课程：展示为立刻购买或加入购物车
            log.error("用户：{}，课程：{}，未查询到用户课表中指定课程状态", userId, courseId);
            return null;
        }
        return BeanUtil.copyProperties(lesson, LearningLessonVo.class);
    }

    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        //TODO day02 4.1统计课程的学习人数
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getCourseId, courseId);
        return this.count(queryWrapper);
    }

    private CourseSimpleInfoDTO getCourse(Long courseId, List<CourseSimpleInfoDTO> simpleInfoList) {
        Optional<CourseSimpleInfoDTO> any = simpleInfoList.stream().filter(c -> Objects.equals(c.getId(), courseId)).findAny();
        if (any.isPresent()) {
            return any.get();
        }
        return null;
    }
}
